/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.semi.fw;

import com.semi.util.StringUtil;
import com.semi.util.FileLogger;
import com.semi.util.TimeUtil;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

/**
 *
 * @author liaoyq
 */
public class CodeCenter {
    private final FileLogger mLogger = new FileLogger(CodeCenter.class.getName());
    public UnCoderMgr mCoders = new UnCoderMgr();
    public UnIPMgr mIPs = new UnIPMgr();
    public FwCmd mExecute = null;
    private ConsoleNioThrd mNioConsole = null;
    private ConsoleThrd mConsole = null;
    private String mDev = "FW";
    private int mConsoleTimeout = 0;
    private int mConsolePort = 8110;
    public String name(){ return mDev; };
    public String version(){ return "1.1.0.3"; }
    public void setName(String n){
        if( n==null ) return;
        if( n.length()<1 ) return;
        mDev = n;
    }
    public int ConsoleTimeout(){ return mConsoleTimeout*1000; };
    public void setConsoleTimeout(int n){ if( n>=0 )mConsoleTimeout =n; };
    public int ConsolePort(){ return mConsolePort; };
    public void setConsolePort(int p){ if( p>0 ) mConsolePort = p; };
    public  void setup(String name){
        mExecute = new FwCmd(this);
        Element root = createDocument(name);
        if( root==null ) return;
        Element a;
        mIPs.clear();
        mCoders.clear();        
        a = root.getChild("console");
        if( a!=null ){
            boolean nio = false;
            setName(a.getAttributeValue("name"));
            setConsoleTimeout(StringUtil.convertToint(a.getAttributeValue("timeout"), 0));
            nio = StringUtil.convertToBool(a.getAttributeValue("nio"),false);
            setConsolePort (StringUtil.convertToint(a.getAttributeValue("port"),8110));            
            readRules();
            if( !nio ){
                mConsole = new ConsoleThrd(this);
                //mConsole = new ConsoleNioThrd(this);
                mConsole.start();
            } else {
                mNioConsole = new ConsoleNioThrd(this);
                mNioConsole.start();
            }
        }        
    }    
    public  void shutdown(){
        if( mConsole!=null ){
            mConsole.closeWait();
        }
        if( mNioConsole !=null ){
            mNioConsole.closeWait();
        }
    }
    
    public static String getRemortIP(HttpServletRequest request) {  
      if (request.getHeader("x-forwarded-for") == null) {  
       return request.getRemoteAddr();  
      }  
      return request.getHeader("x-forwarded-for");  
     }      
    protected String findCharset(String s){
        String[] v = s.split(";|=");
        if( v.length<3 ) return null;
        if( (v.length%2)!=1 ) return null;
        for(int i=1;i<v.length;i+=2){
            if( "charset".compareToIgnoreCase(v[i].trim())==0 ) return v[i+1].trim();
        }
        return null;
    }
    public   boolean validateCode(HttpServletRequest request,String encoding){
        String ip = getRemortIP(request);
        String mh = request.getMethod();
        String v = "";
        if(mh.equalsIgnoreCase("POST")){
        	String ctp = request.getHeader("Content-Type");
        	if(ctp != null && ctp.indexOf("application/x-www-form-urlencoded")!= -1){
                    try {
                        mh = findCharset(ctp);
                        mLogger.debug("check encoding "+mh+" for "+ctp);
                        if( mh!=null ) request.setCharacterEncoding(mh);
                        else if( encoding!=null ) request.setCharacterEncoding(encoding);
                    } catch (UnsupportedEncodingException ex) {
                       mLogger.debug("set charset "+ex.getMessage());
                    }
        		Map requestParams = request.getParameterMap(); 
                        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {   
                            String name = (String) iter.next();   
                            String[] values = (String[]) requestParams.get(name);   
                            v += name;
                            for (int i = 0; i < values.length; i++) v+=" "+values[i];
                        }                          
        	}
        }else{
        	v = request.getQueryString();
      	}
        if( v==null ) return false;
        mLogger.debug("check "+ip+" for ["+v+"]");
        int k = mIPs.match(ip);
        if( k >-1 ){
            mLogger.info("[1] black ip="+ip+" used rule="+k);
            return true;
        }
        k = mCoders.match(v);
        if( k>-1){
            mLogger.info("[2] block ip="+ip+" used rule="+k+" name="+mCoders.get(k).mName);
            return true;
        }
        return false;
    }
    private static Element createDocument(String name)  {
        try {
          URL url = Thread.currentThread().getContextClassLoader().getResource(name);
          Document doc = new SAXBuilder().build(url);
          return doc.getRootElement();
        }   catch (RuntimeException rex) {
          throw rex;
        } catch (Exception ex) {
          throw new RuntimeException(ex);
        }
    }
    public void readRules(){
        try {
            URL url = Thread.currentThread().getContextClassLoader().getResource("fw.conf");
            if( url==null ) {
                mLogger.info("waring not foud fw.conf");
                return;
            }
            mLogger.info("read rule to file "+ url.getPath());
            FileReader in = new FileReader(url.getPath());
            BufferedReader reader = new BufferedReader(in);
            String line;
            FwUser u = new FwUser(null,this);
            FwCmd cm = new FwCmd(this);
            cm.execute("sys", u);
            while ((line = reader.readLine()) != null){ 
                if( line.length()<1 ) continue;
                if( line.charAt(0)=='#' ) continue;
                mLogger.info(line);
                mLogger.info(cm.execute(line, u));
            }            
        }   catch (RuntimeException rex) {
          throw rex;
        } catch (Exception ex) {
          mLogger.info("load error",ex);
        }        
    }
    public String save(){
        String filePath="";
        URL url = Thread.currentThread().getContextClassLoader().getResource("fw.conf");
        if( url==null ) {
            url = Thread.currentThread().getContextClassLoader().getResource("/");
            filePath = url.getPath()+"fw.conf";
        } else filePath = url.getPath();
        mLogger.info("save rule to file "+ filePath);
        FileWriter fileWriter = null;            
        try {
            fileWriter = new FileWriter(filePath, false);
            fileWriter.write("# Generated by fire wall  v"+version()+" on  "+TimeUtil.getCurrentTimeInString()+StringUtil.CRLF);
            UnRule data ;
            fileWriter.write("# Rule for ip"+StringUtil.CRLF);
            for(int i=0;i<mIPs.size();i++){
                data = mIPs.get(i);
                if( data==null ) continue;
                fileWriter.write(data.toCmd()+StringUtil.CRLF);
            }
            fileWriter.write("# Rule for coder"+StringUtil.CRLF);
            for(int i=0;i<mCoders.size();i++){
                data = mCoders.get(i);
                if( data==null ) continue;
                fileWriter.write(data.toCmd()+StringUtil.CRLF);
            }            
            fileWriter.write("# Completed on "+TimeUtil.getCurrentTimeInString()+StringUtil.CRLF);
            fileWriter.close();
        } catch (IOException ex) {
            return ex.getMessage();
        }
        return "save rule to file "+ filePath;
    }

}
